package com.young.socket.websocket;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Component
@DependsOn(value = "webSocketService")
@ServerEndpoint(value = "/socket/{userId}", configurator = WebSocketConfig.class)
public class WebSocketServer {

    // 记录连接人数。
    private volatile static AtomicInteger onlineCount = new AtomicInteger();

    // concurrent包的线程安全Set，用来存放每个客户端对应的WebSocketServer对象。
    private volatile static ConcurrentMap<String, Session> sessionPools = new ConcurrentHashMap<>();

    private volatile static WebSocketService webSocketService;

    public WebSocketServer() {
        log.info("===============初始化了WebSocketServer===============");
    }

    @Autowired
    public void setWebSocketService(WebSocketService webSocketService) {
        this.webSocketService = webSocketService;
    }

    @PostConstruct
    public void init() {
        if (null == webSocketService.getSocketMessageHandle()) {
            SocketMessageHandle socketMessageHandle = new SocketMessageHandle() {
                @Override
                public void handle(String sessionId, String msg) {
                    try {
                        sendMessage(sessionId, msg);
                    } catch (Exception e) {
                        webSocketService.removeUserSessionId(sessionId);
                        log.error("给客户端推送消息异常：", e);
                    }
                }
            };
            webSocketService.setSocketMessageHandle(socketMessageHandle);
        }
        log.info("===============初始化了SocketMessageHandle===============");
    }

    /**
     * 发送消息方法
     */
    public void sendMessage(String sessionId, String message) throws IOException {
        Session session = sessionPools.get(sessionId);
        if (null != session) {
            session.getBasicRemote().sendText(message);
            log.info("发送消息[{}]给客户端[{}]", message, sessionId);
        } else {
            log.error("Session [{}] is not exist error.", sessionId);
        }
    }

    /**
     * 连接建立成功调用
     */
    @OnOpen
    public void onOpen(@PathParam("userId") String userId, @PathParam("random") String random, Session session) throws IOException {
        synchronized (onlineCount) {
            if (!StringUtils.hasLength(userId)) {
                session.close();
                return;
            }
            String id = session.getId();
            Session oldSession = sessionPools.get(id);
            sessionPools.put(id, session);
            webSocketService.registerUserSessionId(Long.parseLong(userId), session.getId());
            if (null == oldSession) {
                addOnlineCountCount();
                log.info("建立客户端[{}]连接连接, 当前连接数[{}], 当前session[{}]", userId, onlineCount, id);
            } else {
                log.info("建立客户端[{}]连接连接, 当前连接数[{}], 当前session[{}]", userId, onlineCount, oldSession.getId());
            }
        }
    }

    @OnError
    public void onError(Session session, Throwable t) {
        log.error("Socket session of [{}] error!", session.getId(), t);
    }

    /**
     * 关闭连接时调用
     */
    @OnClose
    public void onClose(@PathParam("userId") String userId, Session session) {
        synchronized (onlineCount) {
            Session oldSession = null;
            try {
                if (null != session) {
                    oldSession = sessionPools.remove(session.getId());
                    webSocketService.removeUserSessionId(session.getId());
                    log.info("断开客户端[{}]socket连接！", userId);
                }
                if (null != oldSession) {
                    subOnlineCountCount();
                    log.info("移除客户端[{}]连接, 当前连接客户端数[{}]", userId, onlineCount);
                } else
                    log.info("除客户端[{}]连接失败，session不存在！", userId);
            } catch (Exception e) {
                log.error("移除客户端[{}]连接异常：", userId, e);
            } finally {
                try {
                    if (null != session) session.close();
                    if (null != oldSession) oldSession.close();
                } catch (Exception ignored) {}
            }
        }
    }

    /**
     * 收到客户端消息时触发
     */
    @OnMessage
    public void onMessage(@PathParam("userId") String userId, String message, Session session) {
        try {
            log.info("Socket收到用户[{}]客户端[{}]消息 -> [{}]", userId, session.getId(), message);
            if (StringUtils.hasLength(message)) {
                webSocketService.handleMessage(session.getId(), message);
            }
        } catch (Exception e) {
            log.error("Socket收到客户端[{}]消息异常:", session.getId(), e);
        }

    }

    public static void addOnlineCountCount() {
        onlineCount.incrementAndGet();
    }

    public static void subOnlineCountCount() {
        onlineCount.decrementAndGet();
    }

}
